function identity(arg: any): any {
    return arg;
}
// 泛型写法
function identity1<T>(arg: T): T {
    return arg;
}
// 这些类型变量为任意类型
// 泛型类型
let output:<T>(arg:T)=>T = identity1;
let output1 = identity1<string>("myString")
// 还可以使用带有调用签名的对象字面量来定义泛型函数：
let output2:{<T>(arg:T):T} = identity1;
// 可以使用泛型接口去定义
interface itfT{
    <T>(arg:T): T;
}
// 一个相似的例子，我们可能想把泛型参数当作整个接口的一个参数。 这样我们就能清楚的知道使用的具体是哪个泛型类型（比如： Dictionary<string>而不只是Dictionary）。 这样接口里的其它成员也能知道这个参数的类型了。
interface itfT2<T>{
    (arg:T): T;
}
let output3:itfT = identity1

console.log(output("零三"),output1,output2("good"),output3("beautiful"))



// 泛型类
//泛型类看上去与泛型接口差不多。 泛型类使用（ <>）括起泛型类型，跟在类名后面
class NumFn<T> {
    num?:T;
    add?:(x:T,y:T)=>T
}
let numFn = new NumFn<number>()
numFn.num = 3
numFn.add = (x:number,y:number)=>x+y
let n1n = numFn.add(2,3)
console.log(n1n)


// 泛型约束
// 通过extend接口
interface Lengthwise {
    length: number;
    num:number,
    str?:string
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg);  // Now we know it has a .length property, so no more error
    return arg;
}
loggingIdentity({length: 10, value: 3,num:123});//参数必须满足约束条件



// 在泛型约束中使用类型参数
/*function getProperty(obj:T, key:K) {
    return obj[key];
}
let xxx = { a: 1, b: 2, c: 3, d: 4 };

getProperty(xxx, "a"); // okay*/

function create11<T>(c: {new(): T; }): T {
    return new c();
}
let date11 = create11(Date)
console.log(date11)




// 使用原型属性推断并约束构造函数与类实例的关系。

/*
class BeeKeeper {
    hasMask: boolean;
}

class ZooKeeper {
    nametag: string;
}

class Animal1 {
    numLegs: number;
}

class Bee extends Animal1 {
    keeper: BeeKeeper;
}

class Lion extends Animal1 {
    keeper: ZooKeeper;
}

function createInstance<A extends Animal1>(c: new () => A): A {
    return new c();
}

createInstance(Lion).keeper.nametag;  // typechecks!
createInstance(Bee).keeper.hasMask;   // typechecks!
*/
















